package rdb

import (
	"context"
	"fmt"
	"sync"

	"gitee.com/shoyer/logger"
	"gitee.com/shoyer/service/config"
	"github.com/redis/go-redis/v9"
)

var (
	master *redis.Client
	local  *redis.Client
	other  = make(map[string]*redis.Client)
	client *redis.Client
)

// Init init redis
func Init() {
	if config.GetRedisConnMode() == "ip" {
		connectIP()
	}

	if config.GetRedisConnMode() == "master" || config.GetRedisConnMode() == "all" {
		connectMaster()
	}

	if config.GetRedisConnMode() == "local" || config.GetRedisConnMode() == "all" {
		connectLocal()
	}

	// 和其他服务器建立连接
	if config.GetRedisConnMode() == "all" {
		connectServers()
	}
}

// GetLocal 获取本地redis连接
func GetLocal() *redis.Client {
	if local == nil {
		logger.Fatalf("db is nil, ple check")
	}

	return local
}

// GetRemote 获取远程redis连接, 用于master服务器向slave服务器redis读写数据。
func GetRemote(server string) *redis.Client {
	s := other[server]
	if s == nil {
		logger.Error("redis remote server map not found target server" + server)
		return nil
	}

	return s
}

// GetMaster 获取master redis连接，用于slave服务器向master服务器读取数据。
func GetMaster() *redis.Client {
	if master == nil {
		logger.Fatalf("db is nil, ple check")
	}

	return master
}

// GetDB 获取redis连接
func GetDB() *redis.Client {
	if client == nil {
		logger.Fatalf("db is nil, ple check")
	}

	return client
}

func connectMaster() {
	db := config.GetRedisDB()
	master = redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%s:%s", config.GetMasterIP(), config.GetRedisPort()),
		Password: config.GetRedisPassword(),
		DB:       db,
	})

	_, err := client.Ping(context.Background()).Result()
	logger.PanicErrIfNotNil(err)
	logger.Infof("Connect to master redis successfully.")
}

func connectLocal() {
	db := config.GetRedisDB()
	local = redis.NewClient(&redis.Options{
		Network:  "unix",
		Addr:     "/tmp/redis.sock",
		Password: config.GetRedisPassword(),
		DB:       db,
	})

	_, err := client.Ping(context.Background()).Result()
	logger.PanicErrIfNotNil(err)
	logger.Infof("Connect to local redis successfully.")
}

func connectIP() {
	db := config.GetRedisDB()
	client = redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%s:%s", config.GetRedisIP(), config.GetRedisPort()),
		Password: config.GetRedisPassword(),
		DB:       db,
	})

	_, err := client.Ping(context.TODO()).Result()
	logger.PanicErrIfNotNil(err)
	logger.Infof("Connect to redis successfully " + logger.HiCyan(config.GetRedisIP()+":"+config.GetRedisPort()))
}

func connectServers() {
	// 和其他服务器redis建立连接
	db := config.GetRedisDB()
	servers := config.GetConfigServers()
	mutex := &sync.Mutex{}
	waitGroup := &sync.WaitGroup{}
	for _, server := range servers {
		waitGroup.Add(1)
		go func(server string) {
			defer waitGroup.Done()
			client := redis.NewClient(&redis.Options{
				Addr:     fmt.Sprintf("%s:%s", server, config.GetRedisPort()),
				Password: config.GetRedisPassword(),
				DB:       db,
			})
			mutex.Lock()
			other[server] = client
			mutex.Unlock()

			_, err := client.Ping(context.Background()).Result()
			logger.PanicErrIfNotNil(err)
			logger.Infof("Connect to remote %s redis successfully.", server)
		}(server)
	}

	waitGroup.Wait()
}
